package com.campus.customer.service;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.campus.common.bean.common.PageUtil;
import com.campus.common.bean.common.Resp;
import com.campus.common.enums.OrderStatusEnum;
import com.campus.common.enums.PointsRecordSourceEnum;
import com.campus.common.enums.PointsRecordTypeEnum;
import com.campus.common.enums.UserCouponStatusEnum;
import com.campus.common.exception.BusinessException;
import com.campus.customer.bean.order.OrderQueryParam;
import com.campus.customer.dto.RefundRequestDTO;
import com.campus.customer.dto.RefundResponseDTO;
import com.campus.customer.entity.Merchant;
import com.campus.customer.entity.Order;
import com.campus.customer.entity.OrderGoods;
import com.campus.customer.entity.PointsRecord;
import com.campus.customer.entity.UserCoupon;
import com.campus.customer.feign.RefundFeignClient;
import com.campus.customer.mapper.OrderMapper;
import com.campus.customer.mapper.PointsRecordMapper;
import com.campus.customer.mapper.UserMapper;
import com.campus.customer.vo.order.OrderStatusCountVo;
import com.campus.customer.vo.order.OrderVo;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;

/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author ZhaoYuJie
 * @since 2025-04-02
 */
@Service
@Slf4j
public class OrderService extends ServiceImpl<OrderMapper, Order> {
    @Autowired
    private OrderGoodsService orderGoodsService;
    @Autowired
    private UserCouponService userCouponService;
    @Autowired
    private UserService userService;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private PointsRecordMapper pointsRecordMapper;
    @Autowired
    private MerchantService merchantService;
    @Autowired
    private RefundFeignClient refundFeignClient;

    @Transactional(rollbackFor = Exception.class)
    public String createOrder(Order order, List<OrderGoods> orderGoodsList) {
        this.save(order);
        for (OrderGoods orderGoods : orderGoodsList) {
            orderGoods.setOrderId(order.getId());
        }
        orderGoodsService.saveBatch(orderGoodsList);
        //如果使用了优惠券，则更新优惠券状态为已使用
        if (order.getUserCouponId() != null) {
            userCouponService.update(Wrappers.<UserCoupon>lambdaUpdate()
                    .eq(UserCoupon::getId, order.getUserCouponId())
                    .set(UserCoupon::getStatus, UserCouponStatusEnum.USED.getValue())
                    .set(UserCoupon::getOrderId, order.getId())
                    .set(UserCoupon::getUseTime, LocalDateTime.now()));
        }
        //如果使用了积分，则扣除用户的积分
        if (order.getPointsUsed() != null && order.getPointsUsed() > 0) {
            userMapper.deductPoints(order.getUserId(), order.getPointsUsed());
            //记录积分消费记录
            PointsRecord pointsRecord = new PointsRecord();
            pointsRecord.setUserId(order.getUserId());
            pointsRecord.setPoints(order.getPointsUsed());
            pointsRecord.setType(PointsRecordTypeEnum.CONSUME.getValue());
            pointsRecord.setSource(PointsRecordSourceEnum.ORDER.getValue());
            pointsRecord.setSourceId(order.getId());
            pointsRecord.setDescription("订单使用积分");
            pointsRecordMapper.insert(pointsRecord);
        }

        userService.updateUserInfoToRedis(order.getUserId());

        return order.getId();
    }

    public PageInfo<OrderVo> getOrderVoPage(OrderQueryParam param) {
        PageInfo<Order> pageInfo = PageHelper.startPage(param.getPageNo(), param.getPageSize())
                .doSelectPageInfo(() -> getOrderPage(param));

        List<OrderVo> orderVoList = Lists.newArrayList();
        for (Order order : pageInfo.getList()) {
            OrderVo orderVo = new OrderVo();
            BeanUtil.copyProperties(order, orderVo);
            orderVo.setGoods(orderGoodsService.getOrderGoodsByOrderId(order.getId()));
            orderVoList.add(orderVo);
        }

        return PageUtil.convertPageInfo(pageInfo, orderVoList);
    }

    private List<Order> getOrderPage(OrderQueryParam param) {
        List<Order> orders = baseMapper.selectList(Wrappers.<Order>lambdaQuery()
                .eq(param.getUserId() != null, Order::getUserId, param.getUserId())
                .eq(param.getStatus() != null, Order::getStatus, param.getStatus())
                .orderByDesc(Order::getCreateTime));

        return orders;
    }

    public List<OrderStatusCountVo> getOrderStatusCountList(Integer userId) {
        return baseMapper.getOrderStatusCountList(userId);
    }

    /**
     * 查询超时未支付的订单
     * @param timeoutDate 超时时间点
     * @return 超时未支付的订单列表
     */
    public List<Order> findTimeoutUnpaidOrders(Date timeoutDate) {
        return baseMapper.selectList(Wrappers.<Order>lambdaQuery()
                .eq(Order::getStatus, 1) // 待付款状态
                .lt(Order::getCreateTime, timeoutDate)); // 创建时间小于超时时间点
    }

    /**
     * 取消订单（包含优惠券、积分退还和退款逻辑）
     * @param orderId 订单ID
     * @param cancelReason 取消原因
     * @return 是否取消成功
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelOrder(String orderId, String cancelReason) {
        Order order = this.getById(orderId);
        if (order == null) {
            throw new BusinessException("订单不存在");
        }
        
        // 检查订单状态是否可以取消
        if (order.getStatus() != OrderStatusEnum.PENDING_PAYMENT.getValue() && 
            order.getStatus() != OrderStatusEnum.PENDING_ACCEPTANCE.getValue()) {
            throw new BusinessException("订单状态不允许取消");
        }
        
        // 保存原始订单状态，用于判断是否需要退款
        boolean needRefund = order.getStatus() != OrderStatusEnum.PENDING_PAYMENT.getValue();
        
        // 先执行本地事务操作
        // 1. 更新订单状态为已取消
        order.setStatus(OrderStatusEnum.CANCELLED.getValue());
        order.setStatusText(OrderStatusEnum.CANCELLED.getText());
        order.setCancelReason(cancelReason);
        this.updateById(order);
        
        // 2. 如果使用了优惠券，需要退还优惠券
        if (order.getUserCouponId() != null) {
            userCouponService.update(Wrappers.<UserCoupon>lambdaUpdate()
                    .eq(UserCoupon::getId, order.getUserCouponId())
                    .set(UserCoupon::getStatus, UserCouponStatusEnum.AVAILABLE.getValue())
                    .set(UserCoupon::getOrderId, null)
                    .set(UserCoupon::getUseTime, null));
        }
        
        // 3. 如果使用了积分，需要退还积分
        if (order.getPointsUsed() != null && order.getPointsUsed() > 0) {
            // 退还用户积分
            userMapper.addPoints(order.getUserId(), order.getPointsUsed());
            
            // 记录积分退还记录
            PointsRecord pointsRecord = new PointsRecord();
            pointsRecord.setUserId(order.getUserId());
            pointsRecord.setPoints(order.getPointsUsed());
            pointsRecord.setType(PointsRecordTypeEnum.RETURN.getValue());
            pointsRecord.setSource(PointsRecordSourceEnum.ORDER.getValue());
            pointsRecord.setSourceId(order.getId());
            pointsRecord.setDescription("取消订单退还积分");
            pointsRecordMapper.insert(pointsRecord);

            // 积分变动影响了用户信息，要更新用户信息到Redis
            userService.updateUserInfoToRedis(order.getUserId());
        }
        
        // 4. 如果订单已支付，调用退款接口（退款失败将回滚整个事务）
        if (needRefund) {
            // 获取商户信息
            Merchant merchant = merchantService.getById(order.getMerchantId());
            if (merchant == null || merchant.getSubMchid() == null) {
                throw new BusinessException("商户信息不存在或子商户号未配置");
            }

            RefundRequestDTO refundRequest = new RefundRequestDTO();
            refundRequest.setSubMchid(merchant.getSubMchid());
            refundRequest.setOrderId(order.getId());
            refundRequest.setRefundAmount(order.getActualPay());
            refundRequest.setRefundReason("用户取消订单");
            refundRequest.setRefundType(2); // 2-用户取消
            refundRequest.setOperatorId(order.getUserId());
            refundRequest.setOperatorType(2); // 操作人类型：1-商户，2-用户，3-系统，4-客服
            refundRequest.setRemark("用户主动取消订单");
            refundRequest.setWechatTransactionId(order.getTransactionId());
            
            Resp<RefundResponseDTO> refundResult = refundFeignClient.applyRefund(refundRequest);
            if (!"0".equals(refundResult.getCode())) {
                log.error("订单{}退款申请失败：{}", order.getId(), refundResult.getMessage());
                throw new BusinessException("退款申请失败：" + refundResult.getMessage());
            }
            
            log.info("订单{}退款申请成功，退款单号：{}", order.getId(), refundResult.getData().getRefundNo());
        }

        return true;
    }

}